#ifndef _SQLUTIL_HPP_20120610
#define _SQLUTIL_HPP_20120610

#include <mysql.h>

#include <iostream>
#include <sstream>
#include <vector>
#include <string>

#include "base.hpp"

using namespace std;

namespace SqlUtil
{

	class Field
	{
		public:
			std::vector < std::string > m_name;
			std::vector < enum_field_types > m_type;

		public:
			Field ();
			~Field ();

			bool IsNum (int num);
			bool IsNum (std::string num);
			bool IsDate (int num);
			bool IsDate (std::string num);
			bool IsChar (int num);
			bool IsChar (std::string num);
			bool IsBlob (int num);
			bool IsBlob (std::string num);
			int GetField_NO (std::string field_name);
			int  GetFieldType(int index); 

		public:
			DECL_LOGGER(logger);
	};

	class RecordSet
	{
		public:
			int m_affected_rows;
			uint64_t m_insert_id;

		public:
			bool m_init_field;
			unsigned long *m_lengths;
			int m_field_num;
			Field m_field;
			MYSQL_RES *res;
			MYSQL_ROW row;

		public:
			RecordSet ();
			~RecordSet ();

			int FreeResult();

			int InitFields();

			MYSQL_ROW FetchRow();

			int GetField(const std::string& name, std::string& value)
			{
				int k=m_field.GetField_NO(name);
				if( k<0 ) return -1;

				value=std::string(row[k], m_lengths[k]);
				return 0;
			}

			template<typename T>
				int GetField(const std::string& name, T& value)
				{
					std::string str_value;
					GetField(name, str_value);

					std::stringstream ss;
					ss << str_value;
					ss >> value;

					return 0;
				}

			int GetFieldType(int index)
			{
				return m_field.GetFieldType(index);
			}

			template <typename T>
				int GetField(int index, T & value)
				{
					if (index < 0)
					{
						return -1;
					}

					std::string str_value(row[index], m_lengths[index]);
					std::stringstream ss;
					ss << str_value;
					ss >> value;

					return 0;
				}

			int GetAffectedRows();
			
			int GetFieldNum() const { return m_field_num; }

		public:
			DECL_LOGGER(logger);
	};


	class DataBase
	{
		public:
				DataBase ();
			   ~DataBase ();

			   int Init(const std::string& host
					   , int port
					   , const std::string& user
					   , const std::string& password
					   , const std::string& dbname
					   , int retry_times = 3
					   , int retry_interval = 1);

		private:
			   MYSQL * m_Data;

			   std::string m_host;
			   std::string m_user;
			   std::string m_password;
			   int m_port;
			   std::string m_dbname;

			   bool m_connected;

				int m_retry_times;
				int m_retry_interval;

		public:

			   MYSQL * GetMysql ();

			   int Connect ();
			   void DisConnect();
			   int ExecuteSql(const char *SQL, 
					   uint64_t sql_len,
					   RecordSet& recordset);
			   int MysqlErrno();
			   std::string MysqlError();
			   bool ErrDup();

		public:
			   static std::string EscapeString(const std::string& in);

		public:
			   DECL_LOGGER(logger);
	};


};

#endif 

